From bf573a1e1ef913e309ffcab1feb4bc5ee8da1a3d Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Sat, 5 Sep 2009 15:57:25 +0200 Subject: [PATCH] Have the unit test check if the filter model emits the right signals --- gtk/tests/filtermodel.c | 612 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 610 insertions(+), 2 deletions(-) diff --git a/gtk/tests/filtermodel.c b/gtk/tests/filtermodel.c index 77f7231832..52e0d5102b 100644 --- a/gtk/tests/filtermodel.c +++ b/gtk/tests/filtermodel.c @@ -74,6 +74,218 @@ create_tree_store (int depth, return store; } +/* + * Signal monitor + */ + +typedef enum +{ + ROW_INSERTED, + ROW_DELETED, + ROW_CHANGED, + ROW_HAS_CHILD_TOGGLED, + ROWS_REORDERED, + LAST_SIGNAL +} +SignalName; + +typedef struct +{ + SignalName signal; + GtkTreePath *path; +} +Signal; + + +static Signal * +signal_new (SignalName signal, GtkTreePath *path) +{ + Signal *s; + + s = g_new0 (Signal, 1); + s->signal = signal; + s->path = gtk_tree_path_copy (path); + + return s; +} + +static void +signal_free (Signal *s) +{ + if (s->path) + gtk_tree_path_free (s->path); + + g_free (s); +} + + +typedef struct +{ + GQueue *queue; + GtkTreeModel *client; + guint signal_ids[LAST_SIGNAL]; +} +SignalMonitor; + + +static void +signal_monitor_generic_handler (SignalMonitor *m, + SignalName signal, + GtkTreeModel *model, + GtkTreePath *path) +{ + Signal *s; + + g_return_if_fail (m->client == model); + g_return_if_fail (!g_queue_is_empty (m->queue)); + +#if 0 + /* For debugging: output signals that are coming in. Leaks memory. */ + g_print ("signal=%d path=%s\n", signal, gtk_tree_path_to_string (path)); +#endif + + s = g_queue_peek_tail (m->queue); + + g_return_if_fail (s->signal == signal); + + s = g_queue_pop_tail (m->queue); + + g_return_if_fail (!gtk_tree_path_compare (path, s->path)); + + signal_free (s); +} + +static void +signal_monitor_row_inserted (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + signal_monitor_generic_handler (data, ROW_INSERTED, + model, path); +} + +static void +signal_monitor_row_deleted (GtkTreeModel *model, + GtkTreePath *path, + gpointer data) +{ + signal_monitor_generic_handler (data, ROW_DELETED, + model, path); +} + +static void +signal_monitor_row_changed (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + signal_monitor_generic_handler (data, ROW_CHANGED, + model, path); +} + +static void +signal_monitor_row_has_child_toggled (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED, + model, path); +} + +static void +signal_monitor_rows_reordered (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gint *new_order, + gpointer data) +{ + signal_monitor_generic_handler (data, ROWS_REORDERED, + model, path); +} + +static SignalMonitor * +signal_monitor_new (GtkTreeModel *client) +{ + SignalMonitor *m; + + m = g_new0 (SignalMonitor, 1); + m->client = g_object_ref (client); + m->queue = g_queue_new (); + + m->signal_ids[ROW_INSERTED] = g_signal_connect (client, + "row-inserted", + G_CALLBACK (signal_monitor_row_inserted), + m); + m->signal_ids[ROW_DELETED] = g_signal_connect (client, + "row-deleted", + G_CALLBACK (signal_monitor_row_deleted), + m); + m->signal_ids[ROW_CHANGED] = g_signal_connect (client, + "row-changed", + G_CALLBACK (signal_monitor_row_changed), + m); + m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client, + "row-has-child-toggled", + G_CALLBACK (signal_monitor_row_has_child_toggled), + m); + m->signal_ids[ROWS_REORDERED] = g_signal_connect (client, + "rows-reordered", + G_CALLBACK (signal_monitor_rows_reordered), + m); + + return m; +} + +static void +signal_monitor_free (SignalMonitor *m) +{ + int i; + + for (i = 0; i < LAST_SIGNAL; i++) + g_signal_handler_disconnect (m->client, m->signal_ids[i]); + + g_object_unref (m->client); + + if (m->queue) + g_queue_free (m->queue); + + g_free (m); +} + +static void +signal_monitor_assert_is_empty (SignalMonitor *m) +{ + g_assert (g_queue_is_empty (m->queue)); +} + +static void +signal_monitor_append_signal_path (SignalMonitor *m, + SignalName signal, + GtkTreePath *path) +{ + Signal *s; + + s = signal_new (signal, path); + g_queue_push_head (m->queue, s); +} + +static void +signal_monitor_append_signal (SignalMonitor *m, + SignalName signal, + const gchar *path_string) +{ + Signal *s; + GtkTreePath *path; + + path = gtk_tree_path_new_from_string (path_string); + + s = signal_new (signal, path); + g_queue_push_head (m->queue, s); + + gtk_tree_path_free (path); +} /* * Fixture @@ -85,6 +297,8 @@ typedef struct GtkTreeStore *store; GtkTreeModelFilter *filter; + + SignalMonitor *monitor; } FilterTest; static void @@ -111,6 +325,8 @@ filter_test_setup_generic (FilterTest *fixture, * side. */ fixture->tree_view = gtk_tree_view_new_with_model (filter); + + fixture->monitor = signal_monitor_new (filter); } static void @@ -141,6 +357,202 @@ filter_test_setup_empty_unfiltered (FilterTest *fixture, filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE); } +static GtkTreePath * +strip_virtual_root (GtkTreePath *path, + GtkTreePath *root_path) +{ + GtkTreePath *real_path; + + if (root_path) + { + int j; + int depth = gtk_tree_path_get_depth (path); + int root_depth = gtk_tree_path_get_depth (root_path); + + real_path = gtk_tree_path_new (); + + for (j = 0; j < depth - root_depth; j++) + gtk_tree_path_append_index (real_path, + gtk_tree_path_get_indices (path)[root_depth + j]); + } + else + real_path = gtk_tree_path_copy (path); + + return real_path; +} + +static void +filter_test_append_refilter_signals_recurse (FilterTest *fixture, + GtkTreePath *store_path, + GtkTreePath *filter_path, + int depth, + GtkTreePath *root_path) +{ + int i; + int rows_deleted = 0; + GtkTreeIter iter; + + gtk_tree_path_down (store_path); + gtk_tree_path_down (filter_path); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), + &iter, store_path); + + for (i = 0; i < LEVEL_LENGTH; i++) + { + gboolean visible; + GtkTreePath *real_path; + + gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter, + 1, &visible, + -1); + + if (root_path && + (!gtk_tree_path_is_descendant (store_path, root_path) + || !gtk_tree_path_compare (store_path, root_path))) + { + if (!gtk_tree_path_compare (store_path, root_path)) + { + if (depth > 1 + && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), + &iter)) + { + GtkTreePath *store_copy; + GtkTreePath *filter_copy; + + store_copy = gtk_tree_path_copy (store_path); + filter_copy = gtk_tree_path_copy (filter_path); + filter_test_append_refilter_signals_recurse (fixture, + store_copy, + filter_copy, + depth - 1, + root_path); + gtk_tree_path_free (store_copy); + gtk_tree_path_free (filter_copy); + } + } + + gtk_tree_path_next (store_path); + gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter); + + if (visible) + gtk_tree_path_next (filter_path); + + continue; + } + + real_path = strip_virtual_root (filter_path, root_path); + + if (visible) + { + /* This row will be inserted */ + signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED, + real_path); + signal_monitor_append_signal_path (fixture->monitor, + ROW_HAS_CHILD_TOGGLED, + real_path); + + if (depth > 1 + && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), + &iter)) + { + GtkTreePath *store_copy; + GtkTreePath *filter_copy; + + store_copy = gtk_tree_path_copy (store_path); + filter_copy = gtk_tree_path_copy (filter_path); + filter_test_append_refilter_signals_recurse (fixture, + store_copy, + filter_copy, + depth - 1, + root_path); + gtk_tree_path_free (store_copy); + gtk_tree_path_free (filter_copy); + } + + gtk_tree_path_next (filter_path); + } + else + { + /* This row will be deleted */ + rows_deleted++; + signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED, + real_path); + } + + gtk_tree_path_free (real_path); + + gtk_tree_path_next (store_path); + gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter); + } + + if (rows_deleted == LEVEL_LENGTH + && gtk_tree_path_get_depth (filter_path) > 1) + { + GtkTreePath *real_path; + + gtk_tree_path_up (store_path); + gtk_tree_path_up (filter_path); + + /* A row-has-child-toggled will be emitted on the parent */ + if (!root_path + || (root_path + && gtk_tree_path_is_descendant (store_path, root_path) + && gtk_tree_path_compare (store_path, root_path))) + { + real_path = strip_virtual_root (filter_path, root_path); + signal_monitor_append_signal_path (fixture->monitor, + ROW_HAS_CHILD_TOGGLED, + real_path); + + gtk_tree_path_free (real_path); + } + } +} + +static void +filter_test_append_refilter_signals (FilterTest *fixture, + int depth) +{ + /* A special function that walks the tree store like the + * model validation functions below. + */ + GtkTreePath *path; + GtkTreePath *filter_path; + + path = gtk_tree_path_new (); + filter_path = gtk_tree_path_new (); + filter_test_append_refilter_signals_recurse (fixture, + path, + filter_path, + depth, + NULL); + gtk_tree_path_free (path); + gtk_tree_path_free (filter_path); +} + +static void +filter_test_append_refilter_signals_with_vroot (FilterTest *fixture, + int depth, + GtkTreePath *root_path) +{ + /* A special function that walks the tree store like the + * model validation functions below. + */ + GtkTreePath *path; + GtkTreePath *filter_path; + + path = gtk_tree_path_new (); + filter_path = gtk_tree_path_new (); + filter_test_append_refilter_signals_recurse (fixture, + path, + filter_path, + depth, + root_path); + gtk_tree_path_free (path); + gtk_tree_path_free (filter_path); +} + static void filter_test_enable_filter (FilterTest *fixture) { @@ -152,6 +564,8 @@ static void filter_test_teardown (FilterTest *fixture, gconstpointer test_data) { + signal_monitor_free (fixture->monitor); + g_object_unref (fixture->filter); g_object_unref (fixture->store); } @@ -247,6 +661,9 @@ check_filter_model (FilterTest *fixture) { GtkTreePath *path; + if (fixture->monitor) + signal_monitor_assert_is_empty (fixture->monitor); + path = gtk_tree_path_new (); check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path)); @@ -256,6 +673,9 @@ static void check_filter_model_with_root (FilterTest *fixture, GtkTreePath *path) { + if (fixture->monitor) + signal_monitor_assert_is_empty (fixture->monitor); + check_filter_model_recurse (fixture, gtk_tree_path_copy (path), gtk_tree_path_new ()); @@ -345,20 +765,26 @@ static void filled_hide_root_level (FilterTest *fixture, gconstpointer user_data) { + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2"); set_path_visibility (fixture, "2", FALSE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); set_path_visibility (fixture, "0", FALSE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2"); set_path_visibility (fixture, "4", FALSE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3); /* Hide remaining */ + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); + set_path_visibility (fixture, "1", FALSE); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4); @@ -368,6 +794,11 @@ filled_hide_root_level (FilterTest *fixture, check_filter_model (fixture); /* Show some */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1"); + set_path_visibility (fixture, "1", TRUE); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4); @@ -381,11 +812,13 @@ static void filled_hide_child_levels (FilterTest *fixture, gconstpointer user_data) { + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2"); set_path_visibility (fixture, "0:2", FALSE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3"); set_path_visibility (fixture, "0:4", FALSE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); @@ -404,19 +837,34 @@ filled_hide_child_levels (FilterTest *fixture, check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2); - set_path_visibility (fixture, "0:4", TRUE); /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3"); + /* FIXME: Actually, the filter model should not be emitted the + * row-has-child-toggled signal here. *However* an extraneous emission + * of this signal does not hurt and is allowed. + */ + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3"); + set_path_visibility (fixture, "0:4", TRUE); check_filter_model (fixture); check_level_length (fixture->filter, "0:3", 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2"); set_path_visibility (fixture, "0:2", TRUE); check_filter_model (fixture); check_level_length (fixture->filter, "0:2", LEVEL_LENGTH); check_level_length (fixture->filter, "0:3", LEVEL_LENGTH); check_level_length (fixture->filter, "0:4", 0); + /* FIXME: We are missing a row-has-child-toggled signal for path "0:4" */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0"); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1"); + set_path_visibility (fixture, "0:4:2", TRUE); set_path_visibility (fixture, "0:4:4", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, "0:4", 2); } @@ -474,10 +922,12 @@ filled_vroot_hide_root_level (FilterTest *fixture, check_filter_model_with_root (fixture, path); /* Now test changes in the virtual root level */ + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2"); set_path_visibility (fixture, "2:2", FALSE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3"); set_path_visibility (fixture, "2:4", FALSE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2); @@ -486,6 +936,8 @@ filled_vroot_hide_root_level (FilterTest *fixture, check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3"); set_path_visibility (fixture, "2:4", TRUE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1); @@ -494,6 +946,10 @@ filled_vroot_hide_root_level (FilterTest *fixture, check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); set_path_visibility (fixture, "2:0", FALSE); set_path_visibility (fixture, "2:1", FALSE); set_path_visibility (fixture, "2:2", FALSE); @@ -510,10 +966,13 @@ filled_vroot_hide_root_level (FilterTest *fixture, check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2:4", TRUE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); set_path_visibility (fixture, "2:4", FALSE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 0); @@ -522,6 +981,12 @@ filled_vroot_hide_root_level (FilterTest *fixture, check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1"); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2"); set_path_visibility (fixture, "2:0", TRUE); set_path_visibility (fixture, "2:1", TRUE); set_path_visibility (fixture, "2:2", TRUE); @@ -539,11 +1004,13 @@ filled_vroot_hide_child_levels (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2"); set_path_visibility (fixture, "2:0:2", FALSE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3"); set_path_visibility (fixture, "2:0:4", FALSE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); @@ -562,17 +1029,31 @@ filled_vroot_hide_child_levels (FilterTest *fixture, check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2); - set_path_visibility (fixture, "2:0:4", TRUE); /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3"); + /* FIXME: Actually, the filter model should not be emitted the + * row-has-child-toggled signal here. *However* an extraneous emission + * of this signal does not hurt and is allowed. + */ + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3"); + set_path_visibility (fixture, "2:0:4", TRUE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, "0:3", 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2"); set_path_visibility (fixture, "2:0:2", TRUE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, "0:2", LEVEL_LENGTH); check_level_length (fixture->filter, "0:3", LEVEL_LENGTH); check_level_length (fixture->filter, "0:4", 0); + /* FIXME: We are missing a row-has-child-toggled signal for path "0:4" */ + /* FIXME: Inconsistency! For the non-vroot case we also receive two + * row-has-child-toggled signals here. + */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0"); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1"); set_path_visibility (fixture, "2:0:4:2", TRUE); set_path_visibility (fixture, "2:0:4:4", TRUE); check_level_length (fixture->filter, "0:4", 2); @@ -586,6 +1067,8 @@ empty_show_nodes (FilterTest *fixture, check_filter_model (fixture); check_level_length (fixture->filter, NULL, 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "3", TRUE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, 1); @@ -596,6 +1079,8 @@ empty_show_nodes (FilterTest *fixture, check_level_length (fixture->filter, NULL, 1); check_level_length (fixture->filter, "0", 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0"); set_path_visibility (fixture, "3:2", TRUE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, 1); @@ -603,10 +1088,13 @@ empty_show_nodes (FilterTest *fixture, check_level_length (fixture->filter, "0:0", 1); check_level_length (fixture->filter, "0:0:0", 0); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); set_path_visibility (fixture, "3", FALSE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "3:2:1", TRUE); set_path_visibility (fixture, "3", TRUE); check_filter_model (fixture); @@ -633,6 +1121,8 @@ empty_vroot_show_nodes (FilterTest *fixture, check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2:2", TRUE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 1); @@ -643,10 +1133,13 @@ empty_vroot_show_nodes (FilterTest *fixture, check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 1); + signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0"); set_path_visibility (fixture, "2:2", FALSE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 0); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2:2:1", TRUE); set_path_visibility (fixture, "2:2", TRUE); check_filter_model_with_root (fixture, path); @@ -661,10 +1154,17 @@ unfiltered_hide_single (FilterTest *fixture, gconstpointer user_data) { + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2"); set_path_visibility (fixture, "2", FALSE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals (fixture, 2); filter_test_enable_filter (fixture); check_filter_model (fixture); @@ -676,11 +1176,18 @@ unfiltered_hide_single_child (FilterTest *fixture, gconstpointer user_data) { + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2", FALSE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals (fixture, 2); filter_test_enable_filter (fixture); check_filter_model (fixture); @@ -693,19 +1200,30 @@ unfiltered_hide_single_multi_level (FilterTest *fixture, gconstpointer user_data) { + /* This row is not shown, so its signal is not propagated */ set_path_visibility (fixture, "2:2:2", FALSE); + + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2", FALSE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); check_level_length (fixture->filter, "2:2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals (fixture, 2); filter_test_enable_filter (fixture); check_filter_model (fixture); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2", TRUE); check_filter_model (fixture); @@ -722,10 +1240,18 @@ unfiltered_vroot_hide_single (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2"); set_path_visibility (fixture, "2:2", FALSE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. (We add an additional level to + * take the virtual root into account). + */ + filter_test_append_refilter_signals_with_vroot (fixture, 3, path); filter_test_enable_filter (fixture); check_filter_model_with_root (fixture, path); @@ -739,11 +1265,19 @@ unfiltered_vroot_hide_single_child (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2:2", FALSE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. (We add an additional level to take + * the virtual root into account). + */ + filter_test_append_refilter_signals_with_vroot (fixture, 3, path); filter_test_enable_filter (fixture); check_filter_model_with_root (fixture, path); @@ -758,19 +1292,30 @@ unfiltered_vroot_hide_single_multi_level (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + /* This row is not shown, so its signal is not propagated */ set_path_visibility (fixture, "2:2:2:2", FALSE); + + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2:2", FALSE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); check_level_length (fixture->filter, "2:2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals_with_vroot (fixture, 3, path); filter_test_enable_filter (fixture); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1); + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2:2", TRUE); check_filter_model_with_root (fixture, path); @@ -786,10 +1331,17 @@ unfiltered_show_single (FilterTest *fixture, gconstpointer user_data) { + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2"); set_path_visibility (fixture, "2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals (fixture, 2); filter_test_enable_filter (fixture); check_filter_model (fixture); @@ -801,11 +1353,18 @@ unfiltered_show_single_child (FilterTest *fixture, gconstpointer user_data) { + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals (fixture, 3); filter_test_enable_filter (fixture); check_filter_model (fixture); @@ -814,7 +1373,10 @@ unfiltered_show_single_child (FilterTest *fixture, /* From here we are filtered, "2" in the real model is "0" in the filter * model. */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, 1); check_level_length (fixture->filter, "0", 1); } @@ -824,13 +1386,24 @@ unfiltered_show_single_multi_level (FilterTest *fixture, gconstpointer user_data) { + /* The view is not showing this row (collapsed state), so it is not + * referenced. The signal should not go through. + */ set_path_visibility (fixture, "2:2:2", TRUE); + + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); check_level_length (fixture->filter, "2:2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals (fixture, 3); filter_test_enable_filter (fixture); check_filter_model (fixture); @@ -839,6 +1412,8 @@ unfiltered_show_single_multi_level (FilterTest *fixture, /* From here we are filtered, "2" in the real model is "0" in the filter * model. */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2", TRUE); check_filter_model (fixture); check_level_length (fixture->filter, NULL, 1); @@ -854,10 +1429,17 @@ unfiltered_vroot_show_single (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2"); set_path_visibility (fixture, "2:2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals_with_vroot (fixture, 3, path); filter_test_enable_filter (fixture); check_filter_model_with_root (fixture, path); @@ -871,11 +1453,18 @@ unfiltered_vroot_show_single_child (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2:2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals_with_vroot (fixture, 2, path); filter_test_enable_filter (fixture); check_filter_model_with_root (fixture, path); @@ -884,7 +1473,10 @@ unfiltered_vroot_show_single_child (FilterTest *fixture, /* From here we are filtered, "2" in the real model is "0" in the filter * model. */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2:2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, 1); check_level_length (fixture->filter, "0", 1); } @@ -896,13 +1488,24 @@ unfiltered_vroot_show_single_multi_level (FilterTest *fixture, { GtkTreePath *path = (GtkTreePath *)user_data; + /* The view is not showing this row (collapsed state), so it is not + * referenced. The signal should not go through. + */ set_path_visibility (fixture, "2:2:2:2", TRUE); + + signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2"); set_path_visibility (fixture, "2:2:2", TRUE); + signal_monitor_assert_is_empty (fixture->monitor); check_level_length (fixture->filter, NULL, LEVEL_LENGTH); check_level_length (fixture->filter, "2", LEVEL_LENGTH); check_level_length (fixture->filter, "2:2", LEVEL_LENGTH); + /* The view only shows the root level, so the filter model only has + * the first two levels cached. + */ + filter_test_append_refilter_signals_with_vroot (fixture, 4, path); filter_test_enable_filter (fixture); check_filter_model_with_root (fixture, path); @@ -911,6 +1514,8 @@ unfiltered_vroot_show_single_multi_level (FilterTest *fixture, /* From here we are filtered, "2" in the real model is "0" in the filter * model. */ + signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0"); + signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0"); set_path_visibility (fixture, "2:2", TRUE); check_filter_model_with_root (fixture, path); check_level_length (fixture->filter, NULL, 1); @@ -1214,6 +1819,7 @@ specific_root_mixed_visibility (void) filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL); fixture.filter = GTK_TREE_MODEL_FILTER (filter); + fixture.monitor = NULL; gtk_tree_model_filter_set_visible_column (fixture.filter, 1); @@ -1248,6 +1854,7 @@ specific_has_child_filter (void) fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN); filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL); fixture.filter = GTK_TREE_MODEL_FILTER (filter); + fixture.monitor = NULL; /* We will filter on parent state using a filter function. We will * manually keep the boolean column in sync, so that we can use @@ -1344,6 +1951,7 @@ specific_root_has_child_filter (void) fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN); filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL); fixture.filter = GTK_TREE_MODEL_FILTER (filter); + fixture.monitor = NULL; /* We will filter on parent state using a filter function. We will * manually keep the boolean column in sync, so that we can use -- 2.30.2